package engine;

import java.awt.Point;
import java.util.List;


/**
 * Character.java
 * 
 * @author Connor Gordon, Niel Lebeck
 * 
 *         A sprite object that updates and is in a constant state of change
 * 
 */
public abstract class Character extends Sprite {
    private Point mySpeed;
    private boolean removalFlag;

    /**
     * Moves the character forward by mySpeed. Calls collision response if
     * collision is detected
     * 
     * @param l Level which Character inhabits
     */
    public void move (Level l) {
        CollisionDetector cd = new CollisionDetector();
        getPosition().move((int) (getPosition().getX() + mySpeed.getX()),
                           (int) (getPosition().getY() + mySpeed.getY()));
        List<Sprite> collisionList = cd.doesCollide(this, l.getSpriteList());
        if (collisionList.size() > 0) {
            for (Sprite s : collisionList) {
                Collision c = extractCollisionResponse(s);
                if (c != null) {
                    c.applyCollision(this, s);
                }
            }
        }
    }

    /**
     * Uses reflection to call the appropriate Collision subclass
     * 
     * {Say this character is a Player called Mario and it is colliding with
     * another Character, Goomba.
     * This method will return MarioGoombaCollision -- the name of the
     * appropriate matching collision class}
     * 
     * @param s Sprite which this Character is colliding
     * @return matching collision response
     */
    private Collision extractCollisionResponse (Sprite s) {
        String[] charName = this.getClass().getName().split("\\.");
        String[] spriteName = s.getClass().getName().split("\\.");
        String packageName = "";
        for (int i = 0; i < charName.length - 1; i++) {
            packageName += charName[i];
        }
        String className =
                packageName + "." + charName[charName.length - 1] +
                        spriteName[spriteName.length - 1] + "Collision";
        Collision c = null;
        try {
            c = (Collision) Class.forName(className).newInstance();
        }
        catch (InstantiationException e) {
            e.printStackTrace();
        }
        catch (IllegalAccessException e) {

        }
        catch (ClassNotFoundException e) {
            // System.out.println("No collision class " + className);
        }
        return c;
    }

    /**
     * Returns the character's speed
     * 
     * @return speed of character
     */
    public Point getSpeed () {
        return mySpeed;
    }

    /**
     * Sets new Speed
     * 
     * @param newSpeed next speed
     */
    public void changeSpeed (Point newSpeed) {
        mySpeed = newSpeed;
    }

    /**
     * Updates state of player e.g. this can be change in color, change in size,
     * change in image, etc.
     * Called when Character is updated each Thread call.
     * 
     * @param l Level which character belongs
     */
    public abstract void updateState (Level l);

    /**
     * Updates the character by both updating its state and moving it
     * appropriately
     * 
     * @param l Level which the character belongs
     */
    public void update (Level l) {
        updateState(l);
        move(l);
    }

    /**
     * Marks this Character for removal
     */
    public void markForRemoval () {
        removalFlag = true;
    }

    /**
     * Determines whether or not this character can be removed
     * 
     * @return whether or not the character has been flagged for removal
     */
    public boolean shouldRemove () {
        return removalFlag;
    }
}
